#include "include/cxxstd.h"
#include "include/lib.h"
#include "cxx.test.h"

using namespace zero;

namespace zerotest
{
TestResult trPic;

// class and interface implementation. <([{
class ifacep : virtual public ifacemn, virtual public ifacexx
{
	public:
		virtual void p() = 0;
};

class ifaceq : virtual public ifacep, virtual public ifacen
{
	public:
		virtual void q() = 0;
};

class animal : public grandson, virtual public ifacemn, virtual public ifaceq
{
	public:
		int c;
		animal() : grandson(&trPic) { c = 0x81; tr->newOrder = 0x67; tr->deleteOrder = 0x23; tr->vcall = 0x97; tr->ex = 0x6733; }
		animal(TestResult* v) : grandson(v) { c = 4; tr->newOrder <<= 4; tr->newOrder += 4; }
		virtual ~animal() { tr->deleteOrder <<= 4; tr->deleteOrder += 4; }
		virtual void voo() { tr->vcall <<= 4; tr->vcall += 4; }
		virtual void p() { }
		virtual void q() { }
		virtual void xx() { }
};

class pic_exception : public std::bad_exception
{
	public:
		pic_exception() throw() { }
		virtual ~pic_exception() throw() { }
		virtual const char* what() const throw() { return "pic:zerotest::exception"; }
};
// }])>

animal actors;

// testcases <([{
extern "C" void* _ZTVN8zerotest6animalE;
void ctors()
{
	assert(trPic.newOrder == 0x67);
	assert(trPic.deleteOrder == 0x23);
	assert(trPic.vcall == 0x97);
	assert(trPic.ex == 0x6733);
	unsigned int* mbl = reinterpret_cast<unsigned int*>(&actors);
	unsigned int vtable = reinterpret_cast<unsigned int>(&_ZTVN8zerotest6animalE);
	assert(mbl[0] == vtable + 36);
	assert(mbl[1] == reinterpret_cast<unsigned int>(&trPic));
	assert(mbl[2] == 1);
	assert(mbl[3] == 2);
	assert(mbl[4] == 3);
	assert(mbl[5] == 0x81);
	assert(mbl[6] == vtable + 92);
	assert(mbl[7] == vtable + 152);
	assert(mbl[8] == vtable + 184);
}

void new_delete()
{
	trPic.newOrder = 0;
	trPic.deleteOrder = 0;
	animal* ai = new animal(&trPic);
	assert(trPic.newOrder == 0x1234);
	assert(sizeof(animal) == 36);
	// mbl abbreviates from memory binary layout.
	unsigned int* mbl = reinterpret_cast<unsigned int*>(ai);
	unsigned int vtable = reinterpret_cast<unsigned int>(&_ZTVN8zerotest6animalE);
	assert(mbl[0] == vtable + 36);
	assert(mbl[1] == reinterpret_cast<unsigned int>(&trPic));
	assert(mbl[2] == 1);
	assert(mbl[3] == 2);
	assert(mbl[4] == 3);
	assert(mbl[5] == 4);
	assert(mbl[6] == vtable + 92);
	assert(mbl[7] == vtable + 152);
	assert(mbl[8] == vtable + 184);
	delete ai;
	assert(trPic.deleteOrder == 0x4321);
}

void typeinfo()
{
	animal* ai = new animal(&trPic);
	unsigned int aioffset = reinterpret_cast<unsigned int>(ai);
	void* aioffset0 = reinterpret_cast<void*>(aioffset);
	void* aioffset28 = reinterpret_cast<void*>(aioffset + 28);
	assert(aioffset0 == (inherit*) ai);
	assert(aioffset28 == (ifacep*) ai);
	assert(aioffset28 == (ifaceq*) ai);
	base* b = ai;
	assert(aioffset0 == dynamic_cast<inherit*>(b));
	assert(aioffset28 == dynamic_cast<ifaceq*>(b));
	assert(aioffset28 == dynamic_cast<ifacep*>(b));
	delete ai;
}

void vcall()
{
	trPic.deleteOrder = 0;
	trPic.vcall = 0;
	animal* ai = new animal(&trPic);
	inherit* i = ai;
	i->voo();
	assert(trPic.vcall == 0x4);
	base* b = ai;
	delete b;
	assert(trPic.deleteOrder == 0x4321);
}

void ex3()
{
	try {
		throw pic_exception();
		trPic.ex <<= 4; trPic.ex += 1;
	} catch (test_exception& ex) {
		trPic.ex <<= 4; trPic.ex += 6;
	} catch (std::exception& ex) {
		try {
			trPic.ex <<= 4; trPic.ex += 2;
			throw;
		} catch (std::bad_exception& ex) {
			trPic.ex <<= 4; trPic.ex += 3;
			throw;
		}
	}
}

void ex2()
{
	ex3();
	trPic.ex <<= 4; trPic.ex += 4;
}

void ex1()
{
	try {
		ex2();
	} catch (...) {
		trPic.ex <<= 4; trPic.ex += 5;
	}
}

void exception()
{
	trPic.ex = 0;
	ex1();
	assert(trPic.ex == 0x235);
}
// }])>

extern "C" void pic_entry()
{
	// ctrors test must be placed at the beginning to make sure animal::animal() is called correctly.
	ctors();
	new_delete();
	typeinfo();
	vcall();
	exception();
	throw pic_exception();
}
}

// vim: foldmarker=<([{,}])> foldmethod=marker
